#!/usr/bin/env python3
"""
Git提交信息规范检查工具
确保提交信息遵循Conventional Commits规范
"""

import re
import sys
import subprocess
import argparse
from typing import List, Tuple, Optional


class CommitMessageValidator:
    # Conventional Commits正则表达式
    COMMIT_PATTERN = re.compile(
        r'^(feat|fix|docs|style|refactor|perf|test|chore|build|ci|revert)(\(.+\))?: .{1,50}(\n\n.*)?$'
    )
    
    # 类型描述
    TYPE_DESCRIPTIONS = {
        'feat': '新功能',
        'fix': '修复bug',
        'docs': '文档更新',
        'style': '代码格式化（不影响功能）',
        'refactor': '重构（既不是新功能也不是修复）',
        'perf': '性能优化',
        'test': '添加或修改测试',
        'chore': '构建过程或辅助工具的变动',
        'build': '构建系统或外部依赖的变更',
        'ci': 'CI配置文件和脚本的变更',
        'revert': '回滚之前的提交'
    }
    
    def __init__(self):
        self.errors = []
        self.warnings = []
    
    def validate_message(self, message: str) -> bool:
        """验证提交信息格式"""
        self.errors = []
        self.warnings = []
        
        # 检查是否为空
        if not message.strip():
            self.errors.append("提交信息不能为空")
            return False
        
        # 检查是否符合Conventional Commits格式
        if not self.COMMIT_PATTERN.match(message):
            self.errors.append(
                "提交信息格式不正确。正确格式：类型(范围): 描述\n"
                "例如：feat(crawler): 添加图片下载功能"
            )
            return False
        
        # 检查第一行长度
        first_line = message.split('\n')[0]
        if len(first_line) > 72:
            self.warnings.append("建议第一行不超过72个字符")
        
        # 检查是否有空行分隔正文
        lines = message.split('\n')
        if len(lines) > 2 and lines[1].strip():
            self.warnings.append("建议在标题和正文之间添加空行")
        
        # 检查是否以句号结尾
        if first_line.endswith('.'):
            self.warnings.append("建议标题不以句号结尾")
        
        return len(self.errors) == 0
    
    def get_last_commit_message(self) -> Optional[str]:
        """获取最后一次提交信息"""
        try:
            result = subprocess.run(
                ["git", "log", "-1", "--pretty=%B"],
                capture_output=True,
                text=True,
                check=True
            )
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return None
    
    def check_last_commit(self) -> bool:
        """检查最后一次提交信息"""
        message = self.get_last_commit_message()
        if message is None:
            print("无法获取提交信息")
            return False
        
        return self.validate_message(message)
    
    def print_errors(self):
        """打印错误信息"""
        if self.errors:
            print("错误:")
            for error in self.errors:
                print(f"  - {error}")
    
    def print_warnings(self):
        """打印警告信息"""
        if self.warnings:
            print("警告:")
            for warning in self.warnings:
                print(f"  - {warning}")
    
    def print_help(self):
        """打印帮助信息"""
        print("Conventional Commits 提交规范:")
        print("\n格式: <类型>(<范围>): <描述>")
        print("\n[可选的正文]")
        print("\n[可选的脚注]")
        print("\n类型说明:")
        for commit_type, description in self.TYPE_DESCRIPTIONS.items():
            print(f"  {commit_type}: {description}")
        print("\n示例:")
        print("  feat(crawler): 添加图片下载功能")
        print("  fix(parser): 修复编码检测问题")
        print("  docs(readme): 更新安装说明")


def install_git_hook():
    """安装Git提交钩子"""
    hook_content = """#!/bin/sh
# 提交信息检查钩子

# 设置UTF-8编码
export LANG=zh_CN.UTF-8
export LC_ALL=zh_CN.UTF-8

# 使用run_git_flow_ps.bat检查提交信息
../scripts/run_git_flow_ps.bat validate "$(cat $1)"
exit_code=$?

if [ $exit_code -ne 0 ]; then
    echo ""
    echo "提交信息不符合规范，请参考上述提示修改。"
    echo "使用 'git commit --amend' 修改最后一次提交信息。"
    exit 1
fi
"""
    
    hooks_dir = ".git/hooks"
    commit_msg_file = f"{hooks_dir}/commit-msg"
    
    try:
        with open(commit_msg_file, 'w') as f:
            f.write(hook_content)
        
        # 在Windows上设置可执行权限
        import os
        import stat
        os.chmod(commit_msg_file, os.stat(commit_msg_file).st_mode | stat.S_IEXEC)
        
        print(f"已安装提交钩子到 {commit_msg_file}")
        return True
    except Exception as e:
        print(f"安装提交钩子失败: {e}")
        return False


def main():
    parser = argparse.ArgumentParser(description='Git提交信息规范检查工具')
    subparsers = parser.add_subparsers(dest='command', help='可用命令')
    
    # 检查提交信息命令
    check_parser = subparsers.add_parser('check-commit', help='检查最后一次提交信息')
    
    # 验证特定提交信息命令
    validate_parser = subparsers.add_parser('validate', help='验证指定的提交信息')
    validate_parser.add_argument('message', help='要验证的提交信息')
    
    # 安装钩子命令
    install_parser = subparsers.add_parser('install-hook', help='安装Git提交钩子')
    
    # 帮助命令
    subparsers.add_parser('help', help='显示提交规范帮助')
    
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        return
    
    validator = CommitMessageValidator()
    
    if args.command == 'check-commit':
        if validator.check_last_commit():
            print("✅ 提交信息符合规范")
            exit_code = 0
        else:
            validator.print_errors()
            validator.print_warnings()
            exit_code = 1
        sys.exit(exit_code)
    
    elif args.command == 'validate':
        if validator.validate_message(args.message):
            print("✅ 提交信息符合规范")
            exit_code = 0
        else:
            validator.print_errors()
            validator.print_warnings()
            exit_code = 1
        sys.exit(exit_code)
    
    elif args.command == 'install-hook':
        if install_git_hook():
            print("✅ 提交钩子安装成功")
            print("现在每次提交都会自动检查提交信息格式")
            exit_code = 0
        else:
            print("❌ 提交钩子安装失败")
            exit_code = 1
        sys.exit(exit_code)
    
    elif args.command == 'help':
        validator.print_help()


if __name__ == "__main__":
    main()